#include "tcp_client.h"
#include "esp_log.h"
#include <string.h>
#include <errno.h>
#include "uart_iot.h"
#include "esp_timer.h"     // 用于获取高精度时间戳
#include <freertos/task.h> // 任务相关函数
#include <sys/socket.h>    // socket相关函数
#include <freertos/FreeRTOS.h>
#include <freertos/timers.h>

static bool tcp_connect_to_server(void);

const char *testJsonStr1 = "{\"problem\":1,\"question\":\"0234230130124120\",\"answer\":\"1234234134124123\"}";

static const char *TAG = "TCPClient";

#define CORRECT 1

// 全局变量
static int tcp_socket = -1;
static char *server_ip = NULL;
static int server_port = 0;
static TaskHandle_t send_task_handle = NULL;
static TaskHandle_t recv_task_handle = NULL;
static QueueHandle_t send_queue = NULL;
static SemaphoreHandle_t socket_mutex = NULL;
static TimerHandle_t heartbeat_timer = NULL;
const char *welcome_message = "welcome to server!";

#define TIMEOUT 2

static void tcp_send_heartbeat(TimerHandle_t xTimer)
{
    if (!tcp_is_connected())
        return;

    const char heartbeat[] = "HEARTBEAT";
    const size_t len = strlen(heartbeat);

    // if (xSemaphoreTake(socket_mutex, pdMS_TO_TICKS(100)) == pdPASS) {
    int ret = send(tcp_socket, heartbeat, len, 0);
    if (ret < 0)
    {
        ESP_LOGE(TAG, "Heartbeat send error: %s", strerror(errno));
    }
    else
    {
        ESP_LOGD(TAG, "Heartbeat sent (%d bytes)", ret);
        printf("tcp_send_heartbeat-Heartbeat sent (%d bytes)\n", ret);
    }
    // xSemaphoreGive(socket_mutex);
    // }
}

// 停止心跳定时器
static void tcp_stop_heartbeat(void)
{
    if (heartbeat_timer != NULL)
    {
        // 删除定时器 (提供100ms超时)
        if (xTimerDelete(heartbeat_timer, pdMS_TO_TICKS(100)) == pdPASS)
        {
            ESP_LOGD(TAG, "Heartbeat timer deleted");
        }
        else
        {
            ESP_LOGW(TAG, "Failed to delete heartbeat timer");
        }

        heartbeat_timer = NULL;
        ESP_LOGI(TAG, "Heartbeat stopped");
    }
}

// 启动心跳定时器
static void tcp_start_heartbeat(void)
{
    // 如果定时器已经存在，先停止并删除
    if (heartbeat_timer != NULL)
    {
        tcp_stop_heartbeat(); // 这会删除定时器并将heartbeat_timer置为NULL
    }

    // 创建FreeRTOS软件定时器
    heartbeat_timer = xTimerCreate(
        "tcp_heartbeat",                      // 定时器名称
        pdMS_TO_TICKS(HEARTBEAT_INTERVAL_MS), // 间隔时间
        pdTRUE,                               // 自动重载
        NULL,                                 // 参数
        tcp_send_heartbeat                    // 回调函数
    );

    // 检查定时器创建是否成功
    if (heartbeat_timer == NULL)
    {
        ESP_LOGE(TAG, "Failed to create heartbeat timer");
        return;
    }

    // 启动定时器
    if (xTimerStart(heartbeat_timer, pdMS_TO_TICKS(100)) != pdPASS)
    {
        ESP_LOGE(TAG, "Failed to start heartbeat timer");
        // 修改为正确的API函数
        if (xTimerDelete(heartbeat_timer, pdMS_TO_TICKS(100)) != pdPASS)
        {
            ESP_LOGW(TAG, "Failed to delete created timer");
        }
        heartbeat_timer = NULL;
        return;
    }
}

// TCP发送任务
static void tcp_send_task(void *pvParameters)
{
    TcpPacket packet;

    while (1)
    {
        // 检查是否有数据需要发送
        if (xQueueReceive(send_queue, &packet, pdMS_TO_TICKS(TCP_SEND_INTERVAL_MS)) == pdPASS)
        {
            if (tcp_is_connected())
            {
                // 加锁保护socket操作
                //  xSemaphoreTake(socket_mutex, portMAX_DELAY);

                int bytes_sent = send(tcp_socket, packet.data, packet.length, 0);
                if (bytes_sent < 0)
                {
                    ESP_LOGE(TAG, "Send failed! errno=%d", errno);
                    // 发送失败，关闭连接
                    printf("TCPClient-Send failed! errno=%d,close tcp socket!", errno);
                    close(tcp_socket);
                    tcp_socket = -1;
                }
                else
                {
                    ESP_LOGI(TAG, "Sent %d bytes", bytes_sent);
                }

                //  xSemaphoreGive(socket_mutex);
            }

            // 释放数据包内存
            if (!packet.is_dma)
            {
                free(packet.data);
            }
        }

        // 短延时，避免任务占用过多CPU
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

// TCP接收任务
static void tcp_recv_task(void *pvParameters)
{
    uint8_t rx_buffer[TCP_RECV_BUFFER_SIZE];

    while (1)
    {
        if (tcp_is_connected())
        {
            // 设置接收超时（5秒）
            struct timeval tv;
            tv.tv_sec = TIMEOUT;
            tv.tv_usec = 0;
            setsockopt(tcp_socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv));

            // 加锁保护socket操作
            // xSemaphoreTake(socket_mutex, portMAX_DELAY);

            int bytes_received = recv(tcp_socket, rx_buffer, sizeof(rx_buffer) - 1, 0);

            // xSemaphoreGive(socket_mutex);

            if (bytes_received > 0)
            {
                rx_buffer[bytes_received] = '\0'; // 确保字符串结束
                ESP_LOGI(TAG, "Received %d bytes: %.*s",
                         bytes_received, bytes_received, rx_buffer);
                printf("TCPClient-Received %d bytes:%s\n", bytes_received, rx_buffer);

                // 测试使用代码
                //  strncpy(rx_buffer, testJsonStr1, 128); //测试使用代码
                // 对比接收到到的字符串是否是欢迎信息，“welcome to server!”，不是则进入接收数据解析
                bool is_welcome_message = (strcmp(rx_buffer, welcome_message) == 0);
                if (!is_welcome_message)
                {
                    process_received_data(rx_buffer, bytes_received);
                }
            }
            else if (bytes_received == 0)
            {
                ESP_LOGI(TAG, "Server closed connection");
                printf("TCPClient-Server closed connection!\n");
                close(tcp_socket);
                tcp_socket = -1;
                // 停止心跳定时器
                tcp_stop_heartbeat();
            }
            else if (errno != EAGAIN && errno != EWOULDBLOCK)
            {
                ESP_LOGE(TAG, "Receive error! errno=%d", errno);
                close(tcp_socket);
                tcp_socket = -1;
                // 停止心跳定时器
                printf("TCPClient-Receive error! errno=%d", errno);

                tcp_stop_heartbeat();
            }
        }
        else
        {
            // 尝试重新连接
            if (server_ip && server_port > 0)
            {
                printf("disconnect,try to connect_to_server!\n");
                tcp_connect_to_server();
            }

            // 等待一段时间再重试
            vTaskDelay(pdMS_TO_TICKS(2000)); // 每隔2s重新连接一次
        }

        // 短延时，避免任务占用过多CPU
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

// 连接到服务器
static bool tcp_connect_to_server(void)
{
    struct sockaddr_in dest_addr;
    // 新增：用于存储本地（客户端）地址信息
    struct sockaddr_in local_addr;
    socklen_t addr_len = sizeof(local_addr);

    if (tcp_socket >= 0)
    {
        close(tcp_socket);
        tcp_socket = -1;
    }

    tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (tcp_socket < 0)
    {
        ESP_LOGE(TAG, "Failed to create socket");
        return false;
    }

    dest_addr.sin_addr.s_addr = inet_addr(server_ip);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(server_port);

    // 设置TCP_NODELAY禁用Nagle算法
    int flag = 1;
    setsockopt(tcp_socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));

    // 连接服务器
    int ret = connect(tcp_socket, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
    if (ret != 0)
    {
        ESP_LOGE(TAG, "Socket connect failed: %s", strerror(errno));
        close(tcp_socket);
        tcp_socket = -1;
        return false;
    }

    ESP_LOGI(TAG, "Connected to server %s:%d", server_ip, server_port);
    printf("[Tcp_Client]-Connected to server %s:%d\n", server_ip, server_port);

    // 新增：获取客户端本地端口号
    if (getsockname(tcp_socket, (struct sockaddr *)&local_addr, &addr_len) == 0)
    {
        // ntohs：将网络字节序（大端）转换为主机字节序
        uint16_t client_port = ntohs(local_addr.sin_port);
        ESP_LOGI(TAG, "client_port: %d", client_port);
        printf("[Tcp_Client]-cliennt_port: %d\n", client_port);
    }
    else
    {
        ESP_LOGE(TAG, "client_port_Faild!: %s", strerror(errno));
    }
    // 启动心跳包
    tcp_start_heartbeat();

    return true;
}

// 公共接口实现
void tcp_client_init(const char *ip, int port)
{
    // 保存服务器信息
    server_ip = strdup(ip);
    server_port = port;

    // 创建发送队列
    send_queue = xQueueCreate(TCP_SEND_QUEUE_SIZE, sizeof(TcpPacket));

    // 创建socket互斥锁
    socket_mutex = xSemaphoreCreateMutex();
}

void tcp_client_start(const char *server_ip, int server_port)
{
    tcp_client_init(server_ip, server_port);

    // 启动发送任务
    xTaskCreate(tcp_send_task, "tcp_send_task", 4096, NULL, 3, &send_task_handle);

    // 启动接收任务
    xTaskCreate(tcp_recv_task, "tcp_recv_task", 4096, NULL, 3, &recv_task_handle);

    // 尝试连接服务器
    if (tcp_is_connected())
    {           // 新增检查
        return; // 已连接则跳过重连
    }
    printf("tcp_client_start-tcp_connect_to_server\n");
    tcp_connect_to_server(); // 否则执行重连
}

void tcp_client_stop(void)
{
    // 停止心跳
    tcp_stop_heartbeat();

    if (send_task_handle)
    {
        vTaskDelete(send_task_handle);
        send_task_handle = NULL;
    }

    if (recv_task_handle)
    {
        vTaskDelete(recv_task_handle);
        recv_task_handle = NULL;
    }

    if (tcp_socket >= 0)
    {
        close(tcp_socket);
        tcp_socket = -1;
    }

    if (server_ip)
    {
        free(server_ip);
        server_ip = NULL;
    }

    if (send_queue)
    {
        vQueueDelete(send_queue);
        send_queue = NULL;
    }

    if (socket_mutex)
    {
        vSemaphoreDelete(socket_mutex);
        socket_mutex = NULL;
    }
}

bool tcp_send_data(const uint8_t *data, size_t len)
{
    if (!send_queue || len == 0)
    {
        printf("tcp_send_data() : %d\n", len);
        return false;
    }

    // 创建数据包副本
    TcpPacket packet;
    packet.data = malloc(len);
    if (!packet.data)
    {
        printf("tcp_send_data() !packet.data = true\n");
        return false;
    }
    memcpy(packet.data, data, len);
    packet.length = len;
    packet.is_dma = false;

    // 发送到队列
    if (xQueueSend(send_queue, &packet, pdMS_TO_TICKS(100)) != pdPASS)
    {
        free(packet.data);
        printf("tcp_send_data() xQueueSend(send_queue)=false\n");
        return false;
    }

    return true;
}

bool tcp_is_connected(void)
{
    return tcp_socket >= 0;
}

// 发送答题结果到服务器
int send_answer_result(int question_number, int result_flag)
{
    // 参数校验
    if (question_number < 1)
    {
        ESP_LOGE(TAG, "Invalid question number: %d", question_number);
        return -1;
    }

    // 记录调试信息
    ESP_LOGD(TAG, "Sending answer result: questionId=%d, result=%s",
             question_number,
             result_flag == CORRECT ? "CORRECT" : "INCORRECT");

    // 构建JSON字符串
    // questionId: number;
    // correct: boolean;
    char json_buffer[128];
    int json_length = snprintf(json_buffer, sizeof(json_buffer),
                               "{\"questionId\":%d,\"correct\":%s}",
                               question_number,
                               result_flag == CORRECT ? "true" : "false");

    // 检查JSON构建结果
    if (json_length <= 0)
    {
        ESP_LOGE(TAG, "JSON formatting failed");
        return -2;
    }

    if (json_length >= sizeof(json_buffer))
    {
        ESP_LOGE(TAG, "JSON buffer overflow: needed %d, available %zu",
                 json_length, sizeof(json_buffer));
        return -2;
    }

    // 发送JSON数据
    int bytes_sent = tcp_send_data((uint8_t *)json_buffer, json_length);

    if (bytes_sent <= 0)
    {
        ESP_LOGE(TAG, "TCP send failed: %d", bytes_sent);
        return -3;
    }

    ESP_LOGI(TAG, "Sent answer result: %d bytes", bytes_sent);
    return bytes_sent;
}

void process_question_result(void)
{
    // 获取答题结果标志
    int flag = get_question_result_flag();
    ESP_LOGI(TAG, "Question result flag: %d", flag);

    // 获取问题编号
    int question_number = get_questionNum();
    // 只有在答题正确且问题编号有效时才发送
    if (flag == CORRECT && question_number >= 1)
    {
        int result = send_answer_result(question_number, flag);

        if (result > 0)
        {
            ESP_LOGI(TAG, "Answer result sent successfully");
            printf("Answer result sent successfully\n");
        }
        else
        {
            ESP_LOGE(TAG, "Failed to send answer result: %d", result);
        }
    }
}